package assist.client.gwt.view.ui;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import assist.client.gwt.service.PlayersProvider;
import assist.client.gwt.service.StatsProvider;
import assist.domain.model.Player;
import assist.domain.model.StatsQuery.ShotType;
import assist.domain.model.StatsQuery.StatType;
import assist.domain.model.StatsQuery.Strength;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.ActionCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;

/**
 * Default UI implementation of the SelectStatsView.  Allows user to configure
 * a StatsQuery by selecting the columns and rows that should be in the table.
 */
public class SelectStatsViewImpl extends StatsViewImpl 
    implements SelectStatsView, ValueChangeHandler<List<Player>>
{
    @UiField (provided=true)
    CellList<ShotType> shotTypesList;
    @UiField (provided=true)
    CellList<Strength> strengthsList;
    @UiField (provided=true)
    CellList<StatType> statTypesList;    
    @UiField (provided=true)
    StatsTable statsTable;    
    @UiField (provided=true)
    CellTable<Player> gamePlayersTable;    
    @UiField HasClickHandlers calcStatsLink;
    private Presenter listener;   
    private MultiSelectionModel<Player> playerSelectionModel = new MultiSelectionModel<Player>();
    private PlayersProvider playersProvider;    
    private PlayerWowyPopup playerWowyPopup = new PlayerWowyPopup();
    
    
    public SelectStatsViewImpl(UiBinder<Widget, SelectStatsViewImpl> binder)
    {     
        statsTable = new StatsTable(); 
        this.shotTypesList = this.initStatTypeList(ShotType.class);        
        final SingleSelectionModel<ShotType> shotTypeSelectionModel = new SingleSelectionModel<ShotType>();
        this.shotTypesList.setSelectionModel(shotTypeSelectionModel);
        
        this.strengthsList = this.initStatTypeList(Strength.class);     
        final SingleSelectionModel<Strength> strengthSelectionModel = new SingleSelectionModel<Strength>();
        this.strengthsList.setSelectionModel(strengthSelectionModel);        
        
        this.statTypesList = this.initStatTypeList(StatType.class);
        
        //TODO: Make multi-selection model, with check boxes.
        final SingleSelectionModel<StatType> statTypeSelectionModel = new SingleSelectionModel<StatType>();
        this.statTypesList.setSelectionModel(statTypeSelectionModel);
        statTypeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
            public void onSelectionChange(SelectionChangeEvent event) {
                listener.addColumn(shotTypeSelectionModel.getSelectedObject(), strengthSelectionModel.getSelectedObject(), statTypeSelectionModel.getSelectedObject());
            }
          }); 
        
        this.gamePlayersTable = new CellTable<Player>();
        this.gamePlayersTable.setVisibleRange(0, 40);
        this.gamePlayersTable.addColumn(new PlayerColumn());                
        
        this.gamePlayersTable.setSelectionModel(playerSelectionModel,
                DefaultSelectionEventManager.<Player>createCheckboxManager(1));     
              
        playerSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
            public void onSelectionChange(SelectionChangeEvent event) 
            {

                listener.setPlayerRows(playerSelectionModel.getSelectedSet());
            }

          }); 
        Column<Player, Boolean> checkColumn = new Column<Player, Boolean>(
                new CheckboxCell(true, false)) {
              @Override
              public Boolean getValue(Player object) {
                return playerSelectionModel.isSelected(object);
              }
            };
        this.gamePlayersTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("I<br/>"));
        this.gamePlayersTable.setColumnWidth(checkColumn, 20, Unit.PX);  
        
        Column<Player, StatsProvider.PlayerWowy> multiCheckColumn = new Column<Player, StatsProvider.PlayerWowy>(
              new PlayerWowyCell()) {
              @Override
              public StatsProvider.PlayerWowy getValue(Player player) {
                return getStatsProvider().getPlayerWowy(player);
              }
            };
        this.gamePlayersTable.addColumn(multiCheckColumn, SafeHtmlUtils.fromSafeConstant("M<br/>"));
        this.gamePlayersTable.setColumnWidth(multiCheckColumn, 20, Unit.PX);         
        initWidget(binder.createAndBindUi(this));       
    }
    

    
    class PlayerWowyPopup extends PopupPanel
    {
        CellTable<Player> wowyPlayersTable = new CellTable<Player>();
        private MultiSelectionModel<Player> wowyPlayerSelectionModel = new MultiSelectionModel<Player>();
        private StatsProvider.PlayerWowy playerWowy;
        PlayerWowyPopup()
        {
            super(true); 
            this.setAnimationEnabled(true);
            
            wowyPlayersTable.addColumn(new PlayerColumn());            
            wowyPlayersTable.setVisibleRange(0, 40); 
            wowyPlayersTable.setSelectionModel(wowyPlayerSelectionModel,
                    DefaultSelectionEventManager.<Player>createCheckboxManager(1));
         
                  
            wowyPlayerSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
                public void onSelectionChange(SelectionChangeEvent event) 
                {
                    listener.setWowyRows(playerWowy.getPlayer(), wowyPlayerSelectionModel.getSelectedSet());
                }

              }); 
            Column<Player, Boolean> checkColumn = new Column<Player, Boolean>(
                    new CheckboxCell(true, false)) {
                  @Override
                  public Boolean getValue(Player object) {
                    return wowyPlayerSelectionModel.isSelected(object);
                  }
                };
            wowyPlayersTable.addColumn(checkColumn);
            wowyPlayersTable.setColumnWidth(checkColumn, 20, Unit.PX);              
            this.setWidget(wowyPlayersTable);              
        }
        public void show(StatsProvider.PlayerWowy playerWowy)
        {
            this.playerWowy = playerWowy;
            wowyPlayerSelectionModel.clear();
            for (Player player : this.playerWowy.getPlayerWowys())
            {
                wowyPlayerSelectionModel.setSelected(player, true);
            }
            this.center();
        }
        public void setPlayersProvider(PlayersProvider playersProvider)
        {
            if (!playersProvider.getDataDisplays().contains(this.wowyPlayersTable))
            {
                playersProvider.addDataDisplay(this.wowyPlayersTable);
            }
        }
    }
    
    /**
     * NOTE**************
     * @author alan
     */
    private class PlayerWowyCell extends ActionCell<StatsProvider.PlayerWowy>
    {
        //Action Cell is good, but need custom checkbox to render.
        public PlayerWowyCell()
        {
            super("M", new ActionCell.Delegate<StatsProvider.PlayerWowy>() {
                @Override
                public void execute(StatsProvider.PlayerWowy playerWowy) {
                    playerWowyPopup.show(playerWowy);
                }
              });
        }
        
        @Override
        public void render(Cell.Context context,StatsProvider.PlayerWowy playerWowy, SafeHtmlBuilder sb)
        {
            //TODO: Need a custom drop down checkbox image thigy
            sb.appendHtmlConstant("<div style=\"size:200%;font-weight:bold;\">");
            if (!playerWowy.getPlayerWowys().isEmpty()) {
                sb.appendHtmlConstant("<input type=\"checkbox\" checked=checked/>");
              } else {
                sb.appendHtmlConstant("<input type=\"checkbox\" />");
              }
            sb.appendHtmlConstant("</div>");
        }

    }
    
    
    public static class PlayerColumn extends Column<Player, Player>
    {

        public PlayerColumn()
        {
            super(new PlayerCell());
            // TODO Auto-generated constructor stub
        }

        @Override
        public Player getValue(Player object)
        {
            // TODO This will be gamePlayer.getPlayer().
            return object;
        }
        
    }
    public static class PlayerCell extends AbstractCell<Player>
    {
        @Override
        public void render(Context context, Player player, SafeHtmlBuilder sb)
        {
            if (player == null) {
                return;
             }

              // If the value comes from the user, we escape it to avoid XSS attacks.
              SafeHtml safeValue = SafeHtmlUtils.fromString(player.getName().toString());
           
              sb.appendHtmlConstant("<div>");
              sb.append(safeValue);
              sb.appendHtmlConstant("</div>");
        }
    }    
    
    private <T extends Enum<T>> CellList<T> initStatTypeList(Class<T> type)
    {
        CellList<T> cellList = new CellList<T>(new StatTypeCell<T>());
        ListDataProvider<T> typesProvider =
            new ListDataProvider<T>(new ArrayList<T>(EnumSet.allOf(type)));
        typesProvider.addDataDisplay(cellList);
      
   
        return cellList;
    }     
    
    
    public static class StatTypeCell<T extends Enum<T>> extends AbstractCell<T>
    {
        @Override
        public void render(Context context, T statType, SafeHtmlBuilder sb) {
          /*
           * Always do a null check on the value. Cell widgets can pass null to
           * cells if the underlying data contains a null, or if the data arrives
           * out of order.
           */
          if (statType == null) {
            return;
          }

          // If the value comes from the user, we escape it to avoid XSS attacks.
          SafeHtml safeValue = SafeHtmlUtils.fromString(statType.toString());
       
          sb.appendHtmlConstant("<div>");
          sb.append(safeValue);
          sb.appendHtmlConstant("</div>");
        }
    } 

    private void setPlayersProvider(PlayersProvider playersProvider)
    {     
        this.playersProvider = playersProvider;
        if (!playersProvider.getDataDisplays().contains(this.gamePlayersTable))
        {
            playersProvider.addDataDisplay(this.gamePlayersTable);
        }
        playersProvider.addPlayersChangeHandler(this);
        this.playerWowyPopup.setPlayersProvider(playersProvider);
        this.updatePlayerSelections();
    }
    
    private void updatePlayerSelections()
    {
        this.playerSelectionModel.clear();
        for(Long playerId : getStatsProvider().getStatsQuery().getPlayerIds())
        {
            Player player = this.playersProvider.getPlayer(playerId);
            if (player != null)
            {
                this.playerSelectionModel.setSelected(player, true);
            }
        }
    }
    
    @Override
    public void onValueChange(ValueChangeEvent<List<Player>> event)
    {        
        this.updatePlayerSelections();
    } 
    
     
  

    @UiHandler("calcStatsLink")
    void onClickCalcStats(ClickEvent e)
    {               
        listener.goToShowStats();
    }

    @Override
    public void setPresenter(Presenter listener)
    {
        this.listener = listener;
        this.setStatsProvider(listener.getStatsProvider());
        this.setPlayersProvider(listener.getPlayersProvider());
    }
    

    @Override
    protected StatsTable getStatsTable()
    {
        return this.statsTable;
    }
 
   
    /**
     * Called from Activity to update the Colulmns, since the Provider mechanism
     * ONLY updates rows.
     
    @Override
    public void setStatsQuery(StatsQuery statsQuery)
    {    
        statsTable.setStatsQuery(statsQuery);
    }*/
}
